package cn.virens.web.components.shiro.simple.oauth2;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import cn.hutool.core.util.StrUtil;
import cn.virens.database.enums.UserType;
import cn.virens.exception.APIException;
import cn.virens.web.components.open.oauth.Oauth2Service;
import cn.virens.web.components.shiro.ShiroAuthInterface;
import cn.virens.web.components.shiro.exception.CaptchaErrorException;
import cn.virens.web.components.shiro.token.ChannelTokenOauth2;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthCallback.AuthCallbackBuilder;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;

public class OauthWebAuthorizingFilter extends FormAuthenticationFilter {
	private Logger logger = LoggerFactory.getLogger(OauthWebAuthorizingFilter.class);

	@Autowired
	@Qualifier(ShiroAuthInterface.SHIRO_BEAN_NAME)
	private ShiroAuthInterface shiroAuthInterface;

	@Autowired
	private Oauth2Service mOauth2Service;

	public OauthWebAuthorizingFilter() {
	}

	public OauthWebAuthorizingFilter(String loginUrl) {
		this.setLoginUrl(loginUrl);
	}

	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		return executeLogin(request, response);
	}

	/**
	 * 执行登录操作
	 */
	@Override
	protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
		logger.info("executeLogin,RememberMe:" + isRememberMe(request));

		AuthCallbackBuilder builder = AuthCallback.builder();
		builder.authorization_code(WebUtils.getCleanParam(request, "authorization_code"));
		builder.oauthVerifier(WebUtils.getCleanParam(request, "oauthVerifier"));
		builder.oauthToken(WebUtils.getCleanParam(request, "oauthToken"));
		builder.auth_code(WebUtils.getCleanParam(request, "auth_code"));
		builder.state(WebUtils.getCleanParam(request, "state"));
		builder.code(WebUtils.getCleanParam(request, "code"));

		// 通过第三方授权参数或者用户信息,主要是openid
		AuthResponse<AuthUser> resp = mOauth2Service.loign(builder.build());
		if (resp != null && resp.getCode() == AuthResponseStatus.SUCCESS.getCode()) {
			AuthenticationToken token = createToken(resp.getData(), request);

			try {
				Subject subject = getSubject(request, response);
				subject.login(token);

				return onLoginSuccess(token, subject, request, response);
			} catch (AuthenticationException e) {
				return onLoginFailure(token, e, request, response);
			}
		} else {
			throw new APIException("ERROR", resp.getMsg());
		}
	}

	private AuthenticationToken createToken(AuthUser data, ServletRequest request) {
		if (StrUtil.equals(data.getSource(), AuthDefaultSource.GITEE.toString())) {
			return new ChannelTokenOauth2(data.getUuid(), UserType.GITEE, getHost(request));
		} else if (StrUtil.equals(data.getSource(), AuthDefaultSource.WECHAT.toString())) {
			return new ChannelTokenOauth2(data.getUuid(), UserType.WEIXIN, getHost(request));
		} else {
			throw new APIException("UNKOWN", "未知来源用户");
		}
	}

	/**
	 * 登录成功
	 */
	@Override
	protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
		this.shiroAuthInterface.onLoginSuccess(String.valueOf(token.getPrincipal()), getHost(request));

		return super.onLoginSuccess(token, subject, request, response);
	}

	/**
	 * 登录失败
	 */
	@Override
	protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
		this.shiroAuthInterface.onLoginFailure(String.valueOf(token.getPrincipal()), getHost(request));

		return super.onLoginFailure(token, e, request, response);
	}

	/**
	 * 登录失败
	 */
	@Override
	protected void setFailureAttribute(ServletRequest request, AuthenticationException e) {
		if (e instanceof CaptchaErrorException) {
			request.setAttribute("success", false);
			request.setAttribute("message", "验证码错误");
			request.setAttribute(getFailureKeyAttribute(), e);
		} else if (e instanceof UnknownAccountException) {
			request.setAttribute("success", false);
			request.setAttribute("message", "账号错误");
			request.setAttribute(getFailureKeyAttribute(), e);
		} else if (e instanceof IncorrectCredentialsException) {
			request.setAttribute("success", false);
			request.setAttribute("message", "密码错误");
			request.setAttribute(getFailureKeyAttribute(), e);
		} else {
			request.setAttribute("success", false);
			request.setAttribute("message", "未知错误");
			request.setAttribute(getFailureKeyAttribute(), e);
		}
	}

}
